package com.blockmeta.bbs.businesslibrary.websocket;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import com.blankj.utilcode.util.LogUtils;
import com.blockmeta.bbs.businesslibrary.BuildConfig;
import com.blockmeta.bbs.businesslibrary.pojo.websocket.BasePOJO;
import com.google.protobuf.InvalidProtocolBufferException;

import java.util.Random;

import buf.Return;

/**
 * websocket，消息转发，处理分开三个线程，提高并发能力
 */
public class BlockMetaSocket extends Thread {
    public static final int WHAT_PACKET = 1;        // 封包接收
    public static final int WHAT_CONNTSTATUS = 2;    // 連線狀態
    public static final int WHAT_OPEN_SOCKET = 3;    // 連線
    public static final int WHAT_CLOSE_SOCKET = 4;    // 斷線
    public static final int WHAT_WRITE_PACKET = 5;    // 封包送出

    public static final int CONNECT_OK = 1;        // 連線成功
    public static final int CONNECT_DISCONNECT = 2;        // 斷線(Server斷線)
    public static final int CONNECT_CLOSE = 3;        // 發生異常 請中斷連線(Client異常)

    protected SocketIOManager m_websock;
    protected PacketBase m_work;
    protected Handler m_handler;

    protected String targetAddress;

    public String getTargetAddress() {
        return targetAddress;
    }

    public class LoopingHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case WHAT_PACKET:
                case WHAT_CONNTSTATUS:
                    m_work.dispatch(msg.what, msg.arg2, msg.obj, msg.arg1);
                    break;

                case WHAT_OPEN_SOCKET:

                    String ip = (String) msg.obj;
//                    ip = "http://115.29.214.30:9998";
//                    ip = "http://192.168.199.55:9996";
                    LogUtils.d("author" + "[BlockMetaSocket/WHAT_OPEN_SOCKET]" + ip);
                    closeSockSync(false, msg.arg2, true);
                    m_websock = new SocketIOManager.Builder()
                            .wsUrl("https://socket.blockmeta.com")
                            .build();
                    m_websock.setSocketIOStatusListener(new SocketIOStatusListener() {
                        @Override
                        public void onOpen(Object response) {
                            super.onOpen(response);
                            onConnectStatus(BlockMetaSocket.CONNECT_OK, "ConnectionEstablish");
                        }

                        @Override
                        public void onMessage(Object text) {
                            super.onMessage(text);

//                            BasePOJO pojo = translateToPOJO(text);
//                            //分包机制
//                            dispatchPacket(pojo);

                            try {
                                Return.NormalReturn returnBuf = Return.NormalReturn.parseFrom((byte[]) text);
                                dispatchPacket(returnBuf);
                            } catch (InvalidProtocolBufferException e) {
                                e.printStackTrace();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }


                        @Override
                        public void onReconnect() {
                            super.onReconnect();
                        }

                        @Override
                        public void onClosing(Object reason) {
                            super.onClosing(reason);
//                            onConnectStatus(BlockMetaSocket.CONNECT_DISCONNECT, "ActiveDisconnect");
                        }

                        @Override
                        public void onClosed(Object reason) {
                            super.onClosed(reason);
                            onConnectStatus(BlockMetaSocket.CONNECT_DISCONNECT, "ActiveDisconnect");
                        }

                        @Override
                        public void onFailure(Object response) {
                            super.onFailure(response);
                            onConnectStatus(BlockMetaSocket.CONNECT_CLOSE, "ConnectionEstablish");
                        }
                    });
                    m_websock.startConnect();

                    break;

                case WHAT_CLOSE_SOCKET:
                    closeSockSync(msg.arg1 == 1, msg.arg2, false);
                    break;

                case WHAT_WRITE_PACKET:
                    if (m_websock == null) {
                        LogUtils.d("author" + "[BlockMetaSocket/LoopingHandler/WHAT_OUT_PACKET] Socket is null! BasePOJO=" + msg.obj);
                        return;
                    }
                    if (msg.obj != null) {

                        BasePOJO pojo = (BasePOJO) msg.obj;
                        boolean succeeded;
                        if ("heartbeat".equals(pojo.get_pt())) {
                            succeeded = true;
//                            succeeded = m_websock.sendMessage(pojo.get_pt());
//                            LogUtils.d("author"+"WHAT_WRITE_PACKET heartbeat" );
                        } else {
                            succeeded = m_websock.sendMessage(pojo.get_pt(), pojo.toJsonString());
                            LogUtils.d("author" + "WHAT_WRITE_PACKET" + pojo.toJsonString());
                        }


                        if (!succeeded) {
                            LogUtils.d("author" + "[BlockMetaSocket/LoopingHandler/WHAT_OUT_PACKET] BasePOJO=" + msg.obj);
                        }
                    }

                    break;
            }

        }
    }

//    private BasePOJO translateToPOJO(String text) {
//
//        BasePOJO pojo = null;
//        JSONObject jsonObject = JSONObject.parseObject(text);
//        String event = jsonObject.getString("event");
//        switch (event){
//            case "kline_list":
//                pojo = MyApplication.buildGson().fromJson(jsonObject.getString("data"), ChartUpdate.class);
//                break;
//        }
//
//
//        return pojo;
//    }

    public BlockMetaSocket() {
        m_work = new PacketBase();
        m_handler = new LoopingHandler();
        setDaemon(true);
        start();
        waitLooper();
    }

    public void run() {
        Looper.prepare();
        notifyLooper();
        Looper.loop();
    }

    public void openSock(String ip, int port, int session) {
        this.targetAddress = ip + ":" + port;
        Message msg = m_handler.obtainMessage(WHAT_OPEN_SOCKET);
        Random random = new Random(999);
        int randomInt = random.nextInt(2);//3次以后变成0
        msg.obj = ip + ":" + (port - randomInt);
        msg.arg1 = session;
        msg.arg2 = getSockSession();

        m_handler.removeCallbacksAndMessages(null);
        m_handler.sendMessage(msg);
    }


    public void closeSock(boolean sendEvent) {
        Message msg = m_handler.obtainMessage(WHAT_CLOSE_SOCKET);
        msg.arg1 = sendEvent ? 1 : 0;
        msg.arg2 = getSockSession();

        m_handler.removeCallbacksAndMessages(null);
        m_handler.sendMessage(msg);
    }

    // 送出斷線訊息
    protected synchronized void onConnectStatus(int status, String source) {
        int session = Integer.MIN_VALUE;
//        if (m_websock != null) {
//            session = m_websock.getSession();
//        }
        Message msg = new Message();
        msg.what = BlockMetaSocket.WHAT_CONNTSTATUS;
        msg.arg1 = status;
        msg.arg2 = session;
        msg.obj = source;

        Handler tHandler = m_handler;
        if (tHandler != null) {
            tHandler.sendMessage(msg);
        }
    }



    protected void dispatchPacket(BasePOJO packet) {
        if (BuildConfig.DEBUG) {

//				LogUtil.w("[SocketBase/dispatchPacket] ip: " + m_strIP +
//								" port: " + m_nPort + " packet = " + packet.getPacketType().name(),
//						" Content: " + packet.toJsonString());

        }
        if (m_websock == null) {
            return;
        }

        Message msg = new Message();

        msg.what = BlockMetaSocket.WHAT_PACKET;
        msg.arg2 = m_websock.getSession();
        msg.obj = packet;

        Handler tHandler = m_handler;
        if (tHandler != null) {
            tHandler.sendMessage(msg);
        }
    }

    protected void dispatchPacket(Return.NormalReturn packet) {
        if (BuildConfig.DEBUG) {

//				LogUtil.w("[SocketBase/dispatchPacket] ip: " + m_strIP +
//								" port: " + m_nPort + " packet = " + packet.getPacketType().name(),
//						" Content: " + packet.toJsonString());

        }
        if (m_websock == null) {
            return;
        }

        Message msg = new Message();

        msg.what = BlockMetaSocket.WHAT_PACKET;
        msg.arg2 = m_websock.getSession();
        msg.obj = packet;

        Handler tHandler = m_handler;
        if (tHandler != null) {
            tHandler.sendMessage(msg);
        }
    }

    private void closeSockSync(boolean sendEvent, int targetSockSession, boolean reopen) {
        if (m_websock != null) {

            SocketIOManager sock = m_websock;
            m_websock = null;
            sock.stopConnect();

        }

    }

    public void setPacketEventListener(BlockMetaSocket.IPacketEventListener listener) {
        if (m_work != null) {
            m_work.setPacketEventListener(listener);
        }
    }

    public boolean writePacket(int nPktNo, BasePOJO packet) {
        if (m_handler != null && packet != null) {
            Message msg = m_handler.obtainMessage(WHAT_WRITE_PACKET);
            msg.arg2 = nPktNo;
            msg.obj = packet;
            return m_handler.sendMessage(msg);
        }

        return false;
    }

    protected synchronized void waitLooper() {
        if (m_handler == null) {
            try {
                wait();
                sleep(20L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    protected synchronized void notifyLooper() {
        notify();
    }

    public int getSockSession() {
        if (m_websock == null) {
            return Integer.MIN_VALUE;
        }

        return m_websock.getSession();
    }

    public interface IPacketEventListener {
        void onPacket(int what, int session, Object objPacket, int type);
    }
}
